package cn.lzx.industry.assist;

import cn.lzx.industry.material.People;
import cn.lzx.industry.material.Pig;
import cn.lzx.industry.material.Project;
import org.aspectj.lang.annotation.Pointcut;

/**
 * Created by lizhenxing on 2018/2/2.
 * <p>
 * 多个增强器同时拦截一个切面时
 * 可以使用@Order注解指定拦截器执行的顺序
 * 如果不指定order，则aop会按照随机顺序执行增强器
 *
 * <p>
 * AspectJ语法连接
 * http://jinnianshilongnian.iteye.com/blog/1415606
 */
public class ProcessorAssist {

    /**
     * 类型匹配规则
     * 1. *：匹配任何数量字符
     * 2. ..：匹配任何数量字符的重复，如在类型模式中匹配任何数量子包；而在方法参数模式中匹配任何数量参数
     * 3. +：匹配指定类型的子类型；仅能作为后缀放在类型模式后边
     *
     * 匹配语法
     * 1.注解？ 修饰符? 返回值类型 类型声明?方法名(参数列表) 异常列表？
     *
     * 注解：可选，方法上持有的注解，如@Deprecated；
     * 修饰符：可选，如public、protected；
     * 返回值类型：必填，可以是任何类型模式；“*”表示所有类型；
     * 类型声明：可选，可以是任何类型模式；
     * 方法名：必填，可以使用“*”进行模式匹配；
     * 参数列表：“()”表示方法没有任何参数；“(..)”表示匹配接受任意个参数的方法，“(..,java.lang.String)”表示匹配接受java.lang.String类型的参数结束，且其前边可以接受有任意个参数的方法；“(java.lang.String,..)” 表示匹配接受java.lang.String类型的参数开始，且其后边可以接受任意个参数的方法；“(*,java.lang.String)” 表示匹配接受java.lang.String类型的参数结束，且其前边接受有一个任意类型参数的方法；
     * 异常列表：可选，以“throws 异常全限定名列表”声明，异常全限定名列表如有多个以“
     *
     *
     * AspectJ使用 且（&&）、或（||）、非（！）来组合切入点表达式。
     */


    /**
     * execute方式，向增强器传递参数<br>
     * execute:用于匹配方法执行的连接点
     * 更多语法参考上面的超链接
     */
    @Pointcut(value = "execution(* cn.lzx.industry.factory.MeatFactory.producePig(cn.lzx.industry.material.Pig))&&args(pig)")
    public void pointPigExe(Pig pig) {
    }

    /**
     * within，向增强器传递参数
     * within：使用“within(类型表达式)”匹配指定类型内的方法执行
     *
     * within(cn.javass..*) --> cn.javass包及子包下的任何方法执行
     * within(cn.javass..IPointcutService+) --> cn.javass包或所有子包下IPointcutService类型及子类型的任何方法
     * within(@cn.javass..Secure *) --> 持有cn.javass..Secure注解的任何类型的任何方法.必须是在目标对象上声明这个注解,在接口上声明的对它不起作用
     *
     */
    @Pointcut(value = "within(cn.lzx.industry.factory.ProjectFactory)&&args(project)")
    public void pointProject(Project project) {
    }

    /**
     * 对于this和target 定义切点，其实二者是等效的。
     * 区别在于匹配的执行方法是属于AOP代理对象还是目标对象
     * 针对下面两种特点比较，推荐使用target定义切点
     *
     * demo中，SecurityCheck类被拦截，spring容器会将该类特殊处理,
     * 生成一个代理类，这个代理类可能是SecurityCheckCGLIB或者SecurityCheckJDK
     * 拒绝于生成代理类的方式。
     * 其中代理类就是AOP代理对象，原始类就是目标类.
     *
     */

    /**
     * this：使用“this(类型全限定名)”匹配当前AOP代理对象类型的执行方法；
     *
     * 注意是AOP代理对象的类型匹配，这样就可能包括引入接口方法也可以匹配；
     * 注意this中使用的表达式必须是类型全限定名，不支持通配符
     *
     */
    @Pointcut(value = "this(cn.lzx.industry.factory.Check)&&args(people)")
    public void pointPeopleThis(People people){
    }


    /**
     * target：使用“target(类型全限定名)”匹配当前目标对象类型的执行方法；
     *
     * 注意是目标对象的类型匹配，这样就不包括引入接口也类型匹配；
     * 注意target中使用的表达式必须是类型全限定名，不支持通配符
     */
    @Pointcut(value = "target(cn.lzx.industry.factory.Check)&&args(people)")
    public void pointPeopleTarget(People people){
    }


}
